home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / Inspectors / InspectMe / InspectorManager.m < prev    next >
Text File  |  1995-06-12  |  12KB  |  400 lines

  1. // InspectorManager.m
  2. // By Kevin Brain (ksbrain@zeus.UWaterloo.ca)
  3.  
  4. // A class that manages the displaying of elements of a list of view 
  5. // objects that are periodically displayed and removed from a window.
  6.  
  7. // Compositing techniques and functions from the ToolInspector example
  8. // by Sharon Biocca Zakhour, NeXT Developer Support Team
  9. // You may freely copy, distribute and reuse the code in this example.  
  10. // *Everybody involved* disclaims any warranty of any kind, expressed 
  11. // or implied, as to its fitness for any particular use.
  12.  
  13. #import <objc/NXStringTable.h>
  14. #import <appkit/Panel.h>
  15. #import <appkit/View.h>
  16. #import <appkit/PopUpList.h>
  17. #import <appkit/Matrix.h>
  18. #import <objc/Storage.h>
  19. #import <objc/List.h>
  20. #import <appkit/Application.h>    // for NXApp
  21. #import <dpsclient/wraps.h>        // PScomposite
  22. #import <libc.h>
  23.  
  24. #import "InspectorManager.h"
  25.  
  26. @implementation InspectorManager
  27.  
  28. /* Private functions */
  29. static void 
  30. compositeToBuffer(InspectorManager *self,Window *bufferWindow, float srcX, float srcY, 
  31.   float width, float height, float dstX, float dstY)
  32. {
  33.     [[bufferWindow contentView] lockFocus];
  34.     PScomposite(srcX, srcY, width, height,
  35.         [[self->inspectorPanel contentView] gState], dstX, dstY, NX_COPY);
  36.     [[bufferWindow contentView] unlockFocus];
  37. }
  38.  
  39. static void 
  40. compositeToScreen(InspectorManager *self, Window *bufferWindow, float srcX, float srcY,
  41.   float width, float height, float dstX, float dstY)
  42. {
  43.     [[self->inspectorPanel contentView] lockFocus];
  44.     PScomposite(srcX, srcY, width, height, 
  45.         [[bufferWindow contentView] gState], dstX, dstY, NX_COPY);
  46.     [self->inspectorPanel flushWindow];
  47.     [[self->inspectorPanel contentView] unlockFocus];
  48. }
  49.  
  50. /* instance methods */
  51.  
  52. - init
  53. {
  54.     [super init];
  55.     if ([NXApp loadNibSection:"Inspector.nib" owner:self] == nil)
  56.         NXRunAlertPanel(NULL,"Couldn't load Inspector.nib","OK",NULL,NULL);
  57.     /* Tell the Inspector & Palette panels not to become the key window */
  58.     [inspectorPanel setBecomeKeyOnlyIfNeeded: YES];   /* This will only */
  59.         /* work if you don't miniaturize the panel. */
  60.     [inspectorPanel setFloatingPanel:(BOOL)YES];
  61.     useKeyEquivalents = YES;
  62.     
  63.     inspectorList = [[Storage alloc] initCount:0 elementSize:sizeof(struct inspectorListEntry) 
  64.             description:@encode(struct inspectorListEntry)];
  65.     groupList = [[Storage alloc] initCount:0 elementSize:sizeof(char *) description:"*"];
  66.     visibleInspectors = [[Storage alloc] initCount:0 elementSize:sizeof(unsigned int) description:"i"];
  67.     [revertOKOut removeFromSuperview];
  68.     [popupOut removeFromSuperview];
  69.     [inspectorPanel display];            // to actually remove the controls
  70.     [[inspectorPanel contentView] allocateGState];
  71.  
  72.     /* 'messagePanel' is created in IB as the window containing the message inspector*/
  73.     /* This window is non-deferred and always kept off-screen */
  74.     [self addInspector: messageBox 
  75.         title:[inspectorStrings valueForStringKey: "MessageInspector"] 
  76.         atLocation:LOWERLEFTX :LOWERLEFTY cached:NO cacheWindow:messagePanel];
  77.  
  78.     /* Initialize the Inspector to display "Unapplicable Inspector" message */
  79.     [self showMessage:(const char *)"Not\nApplicable"];
  80.  
  81.     return self;
  82. }
  83.  
  84. - (unsigned int)addInspector:(id)theView title:(const char *)theTitle
  85. {
  86.     return [self addInspector:theView title:theTitle 
  87.             atLocation:LOWERLEFTX :LOWERLEFTY cached:YES cacheWindow:nil];
  88. }
  89.  
  90. - (unsigned int)addInspector:(id)theView title:(const char *)theTitle atLocation:(NXCoord)xLoc :(NXCoord)yLoc
  91.         cached:(BOOL)isCached cacheWindow:(id)theCacheWindow
  92. {
  93.     struct inspectorListEntry tempInspectorEntry;
  94.     NXRect    theViewRect;
  95.     
  96.     tempInspectorEntry.view = theView;
  97.     tempInspectorEntry.showing = NO;
  98.     tempInspectorEntry.cached = isCached;
  99.     tempInspectorEntry.title = malloc(sizeof(char)*(strlen((char *)theTitle)));
  100.     strcpy(tempInspectorEntry.title,theTitle);
  101.  
  102.     if (isCached) {
  103.         if (theCacheWindow == nil) {
  104.             [theView getFrame:&theViewRect];
  105.             theViewRect.origin.x = [inspectorList count];
  106.             tempInspectorEntry.cacheWindow = [[Window alloc] initContent:(const NXRect *)&theViewRect
  107.                 style:(int)NX_PLAINSTYLE
  108.                 backing:(int)NX_RETAINED
  109.                 buttonMask:(int)0
  110.                 defer:(BOOL)NO];
  111.             }
  112.         else
  113.             tempInspectorEntry.cacheWindow = theCacheWindow;
  114.          /* The lockFocus forces the gState to become defined */
  115.         [[[tempInspectorEntry.cacheWindow contentView] allocateGState] lockFocus];
  116.         [[tempInspectorEntry.cacheWindow contentView] addSubview:theView];
  117.         if (theCacheWindow == nil) {
  118.             [theView moveTo:0 :0];    // move view to origin of offscreen buffer content view
  119.             [tempInspectorEntry.cacheWindow display];
  120.             }
  121.         [theView getFrame:&tempInspectorEntry.offscreenRect];
  122. //        [theView display];        // draw in offscreen buffer
  123.         [[tempInspectorEntry.cacheWindow contentView] unlockFocus];
  124.         }
  125.     [inspectorList addElement:&tempInspectorEntry];
  126.     
  127.     [theView moveTo:xLoc :yLoc];
  128.     [theView removeFromSuperview];
  129.     return [inspectorList count]-1;
  130. }
  131.  
  132. - (unsigned int)addGroup:(const char *)theTitle
  133. {
  134.     char *tempTitle;
  135.     unsigned short temp;
  136.     id    tempView;
  137.     
  138.     // add item to PopUpList
  139.     // command-key equivalents for first 9
  140.     if (([groupList count] < 9) && (useKeyEquivalents == YES))
  141.         temp = (unsigned short)[groupList count]+(unsigned short)'1';
  142.     else
  143.         temp = 0;    // no command-key equivalent for rest
  144.     tempView = [[popupOut target] addItem:theTitle 
  145.                         action:@selector(selectGroup:)
  146.                         keyEquivalent:temp];
  147.     [tempView setTarget:self];
  148.     if ([groupList count] == 0) {
  149.         // remove the default 'None' item in PopUpList
  150.         [[popupOut target] removeItemAt:(unsigned int)0];
  151.         [popupOut setTitle:theTitle];
  152.         }
  153.     if ([groupList count] == 1)
  154.         [self showGroupPopUp];
  155.     tempTitle = NXCopyStringBuffer((const char *)theTitle);
  156.     [groupList addElement:&tempTitle];
  157.     return [groupList count]-1;
  158. }
  159.  
  160. - setUseKeyEquivalents:(BOOL)use
  161. {
  162.     useKeyEquivalents = use;
  163.     return self;
  164. }
  165.  
  166. - switchToInspector:(unsigned int)newInspectorNum
  167. {
  168.     struct inspectorListEntry *new,*tempOld;
  169.     View *tempView;
  170.     NXRect tempFrame;
  171.     int i,*tempShowing;
  172.     unsigned cnt = [visibleInspectors count];
  173.     
  174.     new = [inspectorList elementAt:newInspectorNum];
  175.     if (!new) return self;    // not a valid inspector
  176.     if (new->showing == YES) return self;        // if already showing
  177.     /* remove all other inspectors */
  178.     if (cnt)            
  179.         for (i=(int)cnt; i > 0;i--) {
  180.             tempShowing = [visibleInspectors elementAt:i-1];
  181.             tempOld = [inspectorList elementAt:(unsigned int)*tempShowing];
  182.             tempOld->showing = NO;
  183.             tempView = tempOld->view;
  184.             if (tempView != NULL) {
  185.                 [tempView getFrame:&tempFrame];
  186.                 if (tempOld->cached)
  187.                     compositeToBuffer(self, tempOld->cacheWindow, tempFrame.origin.x, tempFrame.origin.y,
  188.                             NX_WIDTH(&tempFrame),NX_HEIGHT(&tempFrame),
  189.                             tempOld->offscreenRect.origin.x, tempOld->offscreenRect.origin.y);
  190.                 [tempView removeFromSuperview];
  191.                 }
  192.             }
  193.     [visibleInspectors empty];
  194.  
  195.     [[inspectorPanel contentView] addSubview:new->view];
  196.     if (new->cached) {
  197.         // Now composite the new inspector view from the offscreen window
  198.         // into the inspector panel
  199.         [new->view getFrame:&tempFrame];
  200.         compositeToScreen(self, new->cacheWindow, new->offscreenRect.origin.x, new->offscreenRect.origin.y, 
  201.             NX_WIDTH(&tempFrame), NX_HEIGHT(&tempFrame), tempFrame.origin.x, tempFrame.origin.y);
  202.         }
  203.     else
  204.         [new->view display];
  205.     
  206.     [inspectorPanel setTitle:new->title];
  207.     new->showing = YES;
  208.     i=(int)newInspectorNum;
  209.     [visibleInspectors addElement:&i];
  210.     
  211.     return self;
  212. }
  213.  
  214. - showInspector:(unsigned int)inspectorNum
  215. {
  216.     struct inspectorListEntry *new;
  217.     NXRect tempFrame;
  218.     int tempNum;
  219.     
  220.     new = [inspectorList elementAt:inspectorNum];
  221.     if (!new) return self;    // not a valid inspector
  222.  
  223.     if ([self showing:inspectorNum] == YES) return self;        // if already showing
  224.  
  225.     [inspectorPanel disableFlushWindow];
  226.     [[inspectorPanel contentView] addSubview:new->view];
  227.     if (new->cached) {
  228.         // Now composite the new inspector view from the offscreen window
  229.         // into the inspector panel
  230.         [new->view getFrame:&tempFrame];
  231.         compositeToScreen(self, new->cacheWindow, new->offscreenRect.origin.x, new->offscreenRect.origin.y, 
  232.             NX_WIDTH(&tempFrame), NX_HEIGHT(&tempFrame), tempFrame.origin.x, tempFrame.origin.y);
  233.         }
  234.     else
  235.         [new->view display]; 
  236.     
  237.     [inspectorPanel setTitle:new->title];
  238.     [inspectorPanel reenableFlushWindow];
  239.     [inspectorPanel flushWindowIfNeeded];
  240.     new->showing = YES;
  241.     tempNum = (int)inspectorNum;
  242.     [visibleInspectors addElement:&tempNum];
  243.     
  244.     return self;
  245. }
  246.  
  247. - hideInspector:(unsigned int)inspectorNum
  248. {
  249.     struct inspectorListEntry *inspector;
  250.     View *tempView;
  251.     NXRect tempFrame;
  252.     int i,cnt = [visibleInspectors count],*tempNum;
  253.     
  254.     inspector = [inspectorList elementAt:inspectorNum];
  255.     if (!inspector) return self;    // not a valid inspector
  256.     if(cnt)            // find inspectorNum is visibleInspectors list
  257.         for (i=cnt; i > 0;i--) {
  258.             tempNum = [visibleInspectors elementAt:i-1];
  259.             if (inspectorNum == (unsigned)*tempNum) {
  260.                 [visibleInspectors removeAt:(unsigned)i-1];
  261.                 inspector->showing = NO;
  262.                 tempView = inspector->view;
  263.                 if (tempView != NULL) {
  264.                     [tempView getFrame:&tempFrame];
  265.                     if (inspector->cached)
  266.                         compositeToBuffer(self, inspector->cacheWindow, 
  267.                                 tempFrame.origin.x, tempFrame.origin.y,
  268.                                 NX_WIDTH(&tempFrame),NX_HEIGHT(&tempFrame),
  269.                                 inspector->offscreenRect.origin.x, inspector->offscreenRect.origin.y);
  270.                     [tempView removeFromSuperview];
  271.                     }
  272.                 }
  273.             }
  274.         
  275.     return self;
  276. }
  277.  
  278. - (BOOL)showing:(unsigned int)inspectorNum
  279. {
  280.     struct inspectorListEntry *inspector;
  281.     
  282.     if (inspectorNum >= [inspectorList count]) return NO;    // not a valid inspector
  283.     else inspector = [inspectorList elementAt:(unsigned)inspectorNum];
  284.  
  285.     if (inspector->showing == YES) return YES;
  286.     else return NO;
  287. }
  288.  
  289. - (int)group
  290. {
  291.     // check if a group is selected (none is initially)
  292.     if ([[popupOut target] selectedItem] == NULL)
  293.         return 0;    // if no group selected, return default group (first group added)
  294.     else
  295.         return [[popupOut target] indexOfItem:[[popupOut target] selectedItem]];
  296. }
  297.  
  298. - showMessage:(const char *)theMessage
  299. {
  300.     [inspectorPanel disableFlushWindow];
  301.     [self switchToInspector:MESSAGE];
  302.     [messageTextField setStringValue:theMessage];
  303.     [messageTextField display];
  304.     [[inspectorPanel reenableFlushWindow] flushWindowIfNeeded];
  305.     return self;
  306. }
  307.  
  308. - messageTextField {return messageTextField; }
  309.  
  310. - panel
  311. {
  312.     return inspectorPanel;
  313. }
  314.  
  315. - popUpListButton
  316. {
  317.     return popupOut;
  318. }
  319.  
  320. - revertOKMatrix
  321. {
  322.     return revertOKOut;
  323. }
  324.  
  325. - setDelegate:(id)anObject
  326. {
  327.     delegate = anObject;
  328.     return self;
  329. }
  330.  
  331. - delegate
  332. {
  333.     return delegate;
  334. }
  335.  
  336. - selectGroup:sender
  337. // target of inspector panel group selector PopUpList
  338. {
  339.     [popupOut setTitle:[[sender selectedCell] title]];
  340.     [inspectorPanel orderFront:self];
  341.     if ([delegate respondsTo:@selector(groupChanged:to:)]) 
  342.     {
  343.         [delegate groupChanged:self to:[sender selectedRow]];
  344.     }
  345.     return self;
  346. }
  347.  
  348. - revertPressed:sender
  349. // target of inspector panel Revert button
  350. {
  351.     if ([delegate respondsTo:@selector(inspectRevert)]) 
  352.     {
  353.         [delegate inspectRevert:self];
  354.     }
  355.     return self;
  356. }
  357.  
  358. - okPressed:sender
  359. // target of inspector panel OK button
  360. {
  361.     if ([delegate respondsTo:@selector(inspectOK)]) 
  362.     {
  363.         [delegate inspectOK:self];
  364.     }
  365.     return self;
  366. }
  367.  
  368. - showRevertOK
  369. {
  370.     [[inspectorPanel contentView] addSubview:revertOKOut];
  371.     [revertOKOut display];
  372.     return self;
  373. }
  374.  
  375. - hideRevertOK
  376. {
  377.     [revertOKOut removeFromSuperview];
  378.     // uncomment the following line to have the Revert/OK buttons
  379.     // automatically removed by displaying the contentView 
  380.     // (otherwise the image of the buttons will still be visible)
  381.     //    [[inspectorPanel contentView] display];
  382.     return self;
  383. }
  384.  
  385. - showGroupPopUp
  386. {
  387.     [[inspectorPanel contentView] addSubview:popupOut];
  388.     [popupOut display];
  389.     return self;
  390. }
  391.  
  392. - hideGroupPopUp
  393. {
  394.     [popupOut removeFromSuperview];
  395.     [[inspectorPanel contentView] display];
  396.     return self;
  397. }
  398. @end
  399.  
  400.